#pragma once
#include "rulebase2b.h"
#include"freeformrule.h"
#include<assert.h>
#include <iostream>

//class LongInstance2;

enum discardingOrder
{
	removeleastgainfirst_dynamic,
	removemostgainfirst_dynamic,
	removeleastgainfirst_static,
	removemostgainfirst_static,
	removeoldestfirst,
	removenewestfirst,
	removelinear,
	removelinearreverse,
	removerandom
};


/**
 * This class stores a free form of a rule base. It usually accepts a RuleBase2B in its constructor 
 * and removes the unimportant neighbors. Because different neighbors are deleted for different
 * input rule bases, we also need to store the remaining (i.e. importanr) neighbor names (e.g. n0, n1, n3, n6)
 * \note This class should only be used to compress RuleBase2
 */
class FreeFormRuleBase
{

private:
	vector<FreeFormRule> cmpRule;	//!< Compressed rules, where zero or more features are removed from the original LongInstance2B objects.
	int* neighborIndices;			//!< The indices of the remaining [important] neighbors.
	int compressedNBSize;			//!< Number of remaining neighbors after removing the unimportant neighbors.
	int nbPerRule;
	FreeFormRuleBase ();
	int originalNBSize;				//!< Number of features before starting to eliminate the unimportant ones.
	FreeFormRuleBase& operator= (const FreeFormRuleBase& left);
	/** This function adds a neighbor whose index is given to the current ffrb list of neighbors.
	 * It uses the given EighLayerIM object, leavs the last valid layer for the label, and uses
	 * the previous layers to build the neighbor and its history.
	 *  It is used to add neighbours to the ffrb object during the object cunstruction in
	 * FreeFormRuleBase (string fileName, int layersInIfPart = 1), so we can extend the neighborhood 
	 * till there is no conflict anymore.
	 * \return true if the neighbor with the given index does not already exist in the nbIndices, 
	 * false otherwise.
	 */
	bool addNeighbourToRBWithRepeatingRules(const EightLayerIM& source, int nbIndex);

	/** Similar to the other function above, but accepts the start and end layers to build the nb history.*/
	bool addNeighbourToRBWithRepeatingRules(const EightLayerIM& source, int nbIndex, int startBit, int labelLayer);
	void clearRepeatingRules();
	int countRulesWithLabel (int label) const;
	FreeFormRuleBase (int nbRepRule);//!< This constructor is used only for calculating the information gain of a feature, where we create new objects with the same label.
	
public:
	
	FreeFormRuleBase (const RuleBase2B& rb, bool doCompress = true, discardingOrder order = removelinear);
	FreeFormRuleBase(const FreeFormRuleBase& left);
	/** This constructor expands the neighborhood till there is no more conflict. Does not remove the unneccessary neighbors afterwards.
	*/
	FreeFormRuleBase(string filename, int layersInIfPart = 1);
	FreeFormRuleBase(string filename, int startLayer, int labelLayer);
	
	/** Reads the FreeFormRules from a text file with a specific format. Refer to a sample file to see the format.*/
	//FreeFormRuleBase (string fileName);
	~FreeFormRuleBase();
	void makeObjectFromRB2BandCompress(const RuleBase2B&rb, discardingOrder order);
	void makeObjectFromRB2BandDontCompress(const RuleBase2B&rb);
	
	/** 
	 * This function should only be called ONLY after an object is constructed from a bitmap file (FreeFormRuleBase(string filename, int layersInIfPart = 1);)
	 */
	void removeUnimportantsFromSpiralAddressSpace (discardingOrder order = removeoldestfirst);
	int getcompressedNBSize () const;
	int getNBNumInOneRule () const;
	int getRuleNum () const;
	int getNetInfoSizeInBits() const;
	void removeFeature (int featureIndex);
	int getConflictNum() const;
	bool hasRepeatingRule() const;
	void deleteRulesWithZeroThenPart ();
	FreeFormRule getRule (int index) const;
	double informationContent () const; //!< The total information content of the rule base. Ref. p.378 AI Book.
	double informationGain (int featureInHistory, int historyStep = 0) const; //!< The information gain of a certain feature. Ref. p.379 AI Book
	void getMostGainIndicesArray_SuperposeNBs (int* mGA, int size) const; //!< If there are more than one history in the rules, we get the average gain of the features in the same position in different histories.
	vector<int> getNeighborIndices () const;

	friend ostream& operator<<(ostream& stream,const FreeFormRuleBase& ffrb);
	
};